#include "cleavage.h"

using namespace std;

bool cleavageTrypsin(char curAA, char nextAA)
{
  return (curAA == 'K' || curAA == 'R') && nextAA != 'P';
}

void dissolveProtein(string& protein, 
                     vector<string>& peptides, 
                     bool (*shouldCleave)(char, char))
{
  size_t lastBreak = 0;
  size_t nextBreak = 0;
  size_t finalBreak = 0;
  unsigned int missedCleavages = 0;
  string fullyTryptic;

  for(size_t i = 0; ; i++)
  {
    char curChar = protein[i];

    if(shouldCleave(curChar, protein[i+1]) == true)
    {
      if(i + 1 - lastBreak >= 3)
      {	
	fullyTryptic = protein.substr(lastBreak, i + 1 -lastBreak);
	pushPeptides(fullyTryptic, peptides);
      }

      nextBreak = missedCleavages == 0 ? i + 1 : nextBreak;
      missedCleavages++;
      finalBreak = finalBreak < i + 1 ? i + 1 : finalBreak;

      if(missedCleavages > gMaxMissedCleavages)
      {
        missedCleavages = 0;
        lastBreak = nextBreak;
        i = nextBreak - 1;
        continue;
      }
    }

    //Push back and reset if we reach end of protein
    if(i == protein.size() - 2)
    {
      if(i + 2 - lastBreak >= 3)
      {
	fullyTryptic = protein.substr(lastBreak, i + 2 - lastBreak);
	pushPeptides(fullyTryptic,peptides);
      }

      missedCleavages = 0;
      lastBreak = nextBreak;
      i = nextBreak - 1;

      //If we've really reached the end, then break
      if(lastBreak == finalBreak)
      {
        break;
      }
    }
  }

  //Put the tail on
  if(protein.size() - lastBreak >= 3)
  {
    fullyTryptic = protein.substr(lastBreak, protein.size() - lastBreak);
    pushPeptides(fullyTryptic, peptides);
  }
}

void pushPeptides(string& fullyTryptic,
		  vector<string>& peptides)
{
  unsigned int pepLength = fullyTryptic.size();

  // if fully tryptic
  if(gMinTerminiCleavages == 2)
  {
    peptides.push_back(fullyTryptic);
  }
  // if semitryptic
  if(gMinTerminiCleavages == 1)
  {
    for(unsigned int i = 1; i < pepLength; i++)
    {
      peptides.push_back(fullyTryptic.substr(i, pepLength - i));
      peptides.push_back(fullyTryptic.substr(0,i));
    }
    peptides.push_back(fullyTryptic);
  }
  // if nontryptic
  if(gMinTerminiCleavages == 0)
  {
    for(unsigned int i = 0; i < pepLength; i++)
    {
      for(unsigned int j = 1; j <= pepLength - i; j++)
      {
	peptides.push_back(fullyTryptic.substr(i,j));
      }
    }
  }
}
